home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * grabber_INIT.c
- *
- * Copyright © 1990 Michael Kahl.
- *
- */
-
- #include <asm.h>
- #include <Color.h>
- #include <VRetraceMgr.h>
-
- #include "options.h"
-
-
- /* trap/lo-mem intercepts */
-
- struct intercept {
- short jsr;
- void *new;
- short jmp;
- void *old;
- };
-
- static void intercept_trap(short, struct intercept *, void *);
- static void intercept_lomem(short, struct intercept *, void *);
-
- static void myGNEFilter(void);
- static void myTestControl(void);
- static void myTrackControl(void);
- static void myHiliteControl(void);
- static void myInitCursor(void);
- static void mySetCursor(void);
- static void myWaitMouseUp(void);
- static void myGetMouse(void);
- static void myScrollRect(void);
- static void myGetNextEvent(void);
-
- static struct intercept iJGNE, iTestControl, iTrackControl, iHiliteControl;
- static struct intercept iInitCursor, iSetCursor;
- static struct intercept iWaitMouseUp, iGetMouse, iScrollRect, iGetNextEvent;
-
-
- /* other routines */
-
- static void install_intercepts(void);
- static void get_options(void);
- static void install_VBL(void);
-
- static void filterClick(EventRecord *, char *);
- static void trackMouse(void);
- static void filterScroll(Point *, Rect *);
- static void getEvent(EventRecord *);
-
- static Boolean isScrollBar(ControlHandle);
- static void localize(Point *, WindowPtr);
- static void globalize(Point *, WindowPtr);
- static void GetA4(void);
-
-
- /* global variables */
-
- static ControlHandle theBar, vBar, hBar;
- static short partCode, deltaMax, deltaMin, delta;
- static Boolean triggered, tracking, detached, bounced;
- static Point thePoint, syncPoint, accum, zero;
-
- static struct opt opt = { 1, 0, 0, 0, 0, 1, 1, 1 };
-
-
- /* hand cursor */
-
- static Cursor theGrabber = {
- 0x0180, 0x1A70, 0x2648, 0x264A, 0x124D, 0x1249, 0x6809, 0x9801,
- 0x8802, 0x4002, 0x2002, 0x2004, 0x1004, 0x0808, 0x0408, 0x0408,
- 0x0180, 0x1BF0, 0x3FF8, 0x3FFA, 0x1FFF, 0x1FFF, 0x6FFF, 0xFFFF,
- 0xFFFE, 0x7FFE, 0x3FFE, 0x3FFC, 0x1FFC, 0x0FF8, 0x07F8, 0x07F8,
- 9, 8
- };
-
-
- /* macros */
-
- #define evWhat OFFSET(EventRecord,what)
- #define evModifiers OFFSET(EventRecord,modifiers)
-
- #define INTERVAL 3
- #define MAXRATE 200
- #define FRICTION 2
-
-
- /* ---------- installation ---------- */
-
-
- void
- main(void)
- {
- asm {
- move.l a4,-(sp)
- movea.l a0,a4
- _RecoverHandle
- move.l a0,-(sp)
- _DetachResource
- jsr GetA4
- move.l a4,(a0)
- jsr install_intercepts
- jsr install_VBL
- jsr get_options
- movea.l (sp)+,a4
- }
- }
-
-
- /*
- * install_intercepts
- *
- */
-
- static void
- install_intercepts(void)
- {
- intercept_lomem(0x29A, &iJGNE, myGNEFilter);
- intercept_trap(0xA966, &iTestControl, myTestControl);
- intercept_trap(0xA968, &iTrackControl, myTrackControl);
- intercept_trap(0xA95D, &iHiliteControl, myHiliteControl);
- intercept_trap(0xA850, &iInitCursor, myInitCursor);
- intercept_trap(0xA851, &iSetCursor, mySetCursor);
- intercept_trap(0xA977, &iWaitMouseUp, myWaitMouseUp);
- intercept_trap(0xA972, &iGetMouse, myGetMouse);
- intercept_trap(0xA8EF, &iScrollRect, myScrollRect);
- intercept_trap(0xA970, &iGetNextEvent, myGetNextEvent);
- }
-
-
- /*
- * get_options
- *
- */
-
- static void
- get_options(void)
- {
- Handle r;
-
- if (r = Get1Resource('cnfg', 0))
- opt = * (struct opt *) *r;
- }
-
-
- /* ---------- jGNEFilter intercept ---------- */
-
-
- /*
- * myGNEFilter
- *
- */
-
- static void
- myGNEFilter(void)
- {
- /* see if we want event */
-
- asm {
- tst.b 8(sp)
- beq.s @2 ; event already processed
- cmpi.w #mouseDown,evWhat(a1)
- bne.s @2 ; not a mouse-down event
- }
-
- /* set up registers */
-
- asm {
- movem.l d0-d2/a0-a1/a4,-(sp)
- jsr GetA4
- movea.l (a0),a4
- }
-
- /* see if we're enabled */
-
- if (!opt.enabled)
- goto done;
-
- /* see if we want event */
-
- asm {
- move.b evModifiers(a1),d0
- cmp.b opt,d0
- bne.s @1 ; wrong magic keys
- }
-
- /* process click */
-
- asm {
- pea 32(sp) ; arg: ==> result
- move.l a1,-(sp) ; arg: ==> event
- jsr filterClick
- addq.l #8,sp
- }
-
- /* done */
-
- done:
- asm {
- @1 movem.l (sp)+,d0-d2/a0-a1/a4
- @2 }
- }
-
-
- /*
- * filterClick - process click at jGNEFilter time
- *
- */
-
- static void
- filterClick(register EventRecord *event, char *result)
- {
- Point where = event->where;
- WindowPeek wp;
- int which = FindWindow(where, &wp), refnum;
- ControlHandle cH;
- Rect box;
-
- /* make sure click is in content region of front window */
-
- if (wp) {
- if ((WindowPtr) wp != FrontWindow())
- return;
- if (which == inSysWindow) {
- refnum = wp->windowKind;
- wp->windowKind = userKind;
- which = FindWindow(where, &wp);
- wp->windowKind = refnum;
- }
- }
- if (which != inContent)
- return;
- localize(&where, (WindowPtr) wp);
-
- /* search window's control list for applicable scroll bars */
-
- vBar = hBar = 0;
- for (cH = wp->controlList; cH; cH = (**cH).nextControl) {
- if (!isScrollBar(cH))
- continue;
- box = (**cH).contrlRect;
- if (box.bottom - box.top > box.right - box.left) {
- /* vertical */
- if (!vBar || box.left < (**vBar).contrlRect.left) {
- box.right = box.left;
- box.left = 0;
- if (PtInRect(where, &box))
- vBar = cH;
- }
- }
- else {
- /* horizontal */
- if (!hBar || box.top < (**hBar).contrlRect.top) {
- box.bottom = box.top;
- box.top = 0;
- if (PtInRect(where, &box))
- hBar = cH;
- }
- }
- }
- if (!vBar && !hBar)
- return; /* no applicable scroll bars */
-
- /* track click in scrollable area */
-
- SetCursor(&theGrabber);
- syncPoint = event->where;
- triggered = true;
- tracking = false;
- partCode = delta = 0;
- deltaMax = 2;
- deltaMin = -2;
- accum = zero;
- do {
- if (!WaitMouseUp()) {
- *result = 0;
- event->what = nullEvent; /* just to make sure */
- return;
- }
- } while (!partCode);
-
- /* report click in scroll bar */
-
- event->where = topLeft((**theBar).contrlRect);
- event->where.v += 2;
- event->where.h += 2;
- globalize(&event->where, (WindowPtr) wp);
- thePoint = event->where;
- }
-
-
- /* ---------- TestControl intercept ---------- */
-
-
- /*
- * myTestControl
- *
- * While "grabbing", we return the value of "partCode" regardless. The
- * mouse tracking code requests a scroll by setting "partCode" according
- * to the desired scroll direction. When a scroll is not desired, "partCode"
- * can be set to zero, simulating the mouse being moved outside the scroll
- * arrow.
- *
- */
-
- void
- myTestControl(void)
- {
- asm {
- jsr GetA4
- move.l a4,-(sp)
- movea.l (a0),a4
- tst.b triggered
- beq.s @1 ; not activated
- move.l 16(sp),d0
- cmp.l theBar,d0
- bne.s @1 ; wrong control
- ;
- move.w partCode,20(sp) ; "lie" about where in the control we clicked
- movea.l (sp)+,a4
- addq.l #4,sp
- movea.l (sp)+,a0
- addq.l #8,sp
- jmp (a0) ; return directly to caller
- ;
- @1 movea.l (sp)+,a4 ; chain on to _TestControl
- }
- }
-
-
- /* ---------- TrackControl intercept ---------- */
-
-
- /*
- * myTrackControl
- *
- * All this one does is set a flag so we know when we're inside
- * _TrackControl.
- *
- */
-
- void
- myTrackControl(void)
- {
- asm {
- jsr GetA4
- move.l a4,-(sp)
- movea.l (a0),a4
- tst.b triggered
- beq.s @1
- st tracking
- @1 movea.l (sp)+,a4
- }
- }
-
-
- /* ---------- HiliteControl intercept ---------- */
-
-
- /*
- * myHiliteControl
- *
- * This intercept is for cosmetic purposes only. While "grabbing",
- * we don't want the arrows of the scroll bar to hilite.
- *
- */
-
- void
- myHiliteControl(void)
- {
- asm {
- jsr GetA4
- move.l a4,-(sp)
- movea.l (a0),a4
- tst.b triggered
- beq.s @1
- move.l 14(sp),d0
- cmp.l theBar,d0
- bne.s @1
- clr.w 12(sp) ; set partCode arg to 0 (no hiliting)
- @1 movea.l (sp)+,a4
- }
- }
-
-
- /* ---------- cursor intercepts ---------- */
-
-
- /*
- * myInitCursor
- *
- * This intercept is for cosmetic purposes only. While "grabbing", we don't
- * want the application to disrupt the hand cursor.
- *
- */
-
- void
- myInitCursor(void)
- {
- asm {
- jsr GetA4
- move.l a4,-(sp)
- movea.l (a0),a4
- tst.b triggered
- movea.l (sp)+,a4
- beq.s @1
- addq.l #4,sp ; don't chain on to _InitCursor
- @1 }
- }
-
-
- /*
- * mySetCursor
- *
- * This intercept is for cosmetic purposes only. While "grabbing", we don't
- * want the application to disrupt the hand cursor.
- *
- * If we were really paranoid, we should intercept _SetCCursor as well. But
- * in practice, we only need to worry about "InitCursor()" or "SetCursor(&arrow)".
- *
- */
-
- void
- mySetCursor(void)
- {
- asm {
- jsr GetA4
- move.l a4,-(sp)
- movea.l (a0),a4
- tst.b triggered
- movea.l (sp)+,a4
- beq.s @1
- addq.l #4,sp ; don't chain on to _SetCursor
- move.l (sp)+,(sp)
- @1 }
- }
-
-
- /* ---------- GetMouse intercept ---------- */
-
-
- /*
- * myGetMouse
- *
- * While "grabbing", we lie and say the mouse is in the scroll bar.
- *
- */
-
- void
- myGetMouse(void)
- {
- asm {
- jsr GetA4
- move.l a4,-(sp)
- movea.l (a0),a4
- tst.b triggered
- beq.s @1
- ;
- movea.l 12(sp),a0
- move.l thePoint,(a0)
- move.l a0,-(sp)
- _GlobalToLocal
- movea.l (sp)+,a4
- addq.l #4,sp ; return directly to caller
- move.l (sp)+,(sp)
- rts
- ;
- @1 movea.l (sp)+,a4 ; chain on to real _GetMouse
- }
- }
-
-
- /* ---------- ScrollRect intercept ---------- */
-
-
- /*
- * myScrollRect
- *
- * Most of the work is done by "filterScroll", below.
- *
- * If no scroll is requested (either naturally or as a result of
- * "filterScroll"), we set the revealed region to the empty region
- * and do not chain on to _ScrollRect.
- *
- */
-
- void
- myScrollRect(void)
- {
- asm {
- jsr GetA4
- move.l a4,-(sp)
- movea.l (a0),a4
- tst.b tracking
- beq.s @1
- ;
- move.l 20(sp),-(sp) ; arg: ==> rect
- pea 20(sp) ; arg: ==> dv/dh
- jsr filterScroll
- addq.l #8,sp
- tst.l 16(sp)
- bne.s @1
- ;
- move.l 12(sp),-(sp)
- _SetEmptyRgn
- movea.l (sp)+,a4
- addq.l #4,sp
- movea.l (sp)+,a0
- lea 12(sp),sp ; return directly to caller
- jmp (a0)
- ;
- @1 movea.l (sp)+,a4 ; chain on to _ScrollRect
- }
- }
-
-
- /*
- * filterScroll - process scroll request at _ScrollRect time
- *
- * To enable scrolling faster than the application actually permits,
- * we "accumulate" scroll requests whenever the actual scroll does
- * not catch up to the requested scroll.
- *
- * In this routine we also adjust deltaMin/deltaMax to reflect the
- * perceived scroll increment.
- *
- */
-
- static void
- filterScroll(register Point *d, register Rect *r)
- {
- register short ofs = d->v | d->h;
-
- if (ofs) {
- partCode = 0;
- accum.v += d->v;
- accum.h += d->h;
- if (ofs > deltaMax - deltaMin + 1)
- deltaMin = deltaMax + 1 - ofs;
- else if (ofs < deltaMin - deltaMax - 1)
- deltaMax = deltaMin - 1 - ofs;
- delta -= ofs;
- if (delta < deltaMin || delta > deltaMax) {
- ofs = accum.v | accum.h;
- if (ofs < 0)
- ofs = -ofs;
- if (vBar && ofs < r->bottom - r->top || hBar && ofs < r->right - r->left) {
- *d = zero;
- return; /* let it accumulate */
- }
- }
- syncPoint.v += accum.v;
- syncPoint.h += accum.h;
- *d = accum;
- accum = zero;
- }
- }
-
-
- /* ---------- WaitMouseUp intercept ---------- */
-
-
- /*
- * myWaitMouseUp
- *
- * Most of the work is done by "trackMouse", below.
- *
- * We report the mouse is down as long as we're "grabbing", even if the
- * mouse has actually been released (this is the momentum feature).
- *
- * However, if we need to reverse directions, we have to report that the
- * mouse button has been released, even though it's still down. (In this
- * case, a click in the other scroll arrow is simulated.)
- *
- * Note that D3 is a local variable in _TrackControl that stores the
- * partCode corresponding to the scroll direction.
- *
- */
-
- void
- myWaitMouseUp(void)
- {
- asm {
- jsr GetA4
- move.l a4,-(sp)
- movea.l (a0),a4
- tst.b triggered
- beq.s @1
- jsr trackMouse
- move.b tracking,d0
- beq.s @0
- move.w partCode,d0
- @0 move.b triggered,12(sp)
- @1 movea.l (sp)+,a4
- beq.s @2
- addq.l #4,sp ; don't chain on to real _WaitMouseUp
- tst.b d0
- beq.s @2
- cmp.b d0,d3
- beq.s @2
- sf 4(sp)
- @2 }
- }
-
-
- /*
- * trackMouse - WaitMouseUp processing
- *
- * If the previous scroll request was not honored, we have to assume we've
- * bumped up against the beginning or end of the document. In this case,
- * we need to adjust the syncPoint to the current mouse position. If there
- * is an accumulated scroll, then we've attempted to scroll past the edge, so
- * we have to "bounce". By scrolling one increment in the other direction and
- * back again, we get the application to call _ScrollRect again so we can
- * dispose of the accumulated scroll!
- *
- * If the mouse has moved outside the region corresponding to the current
- * position, we generate a new scroll request.
- *
- */
-
- static void
- trackMouse(void)
- {
- static EventRecord event;
-
- /* see if previous scroll request was skipped */
-
- if (partCode) {
- if (partCode == inDownButton && GetCtlValue(theBar) < GetCtlMax(theBar))
- return;
- if (partCode == inUpButton && GetCtlValue(theBar) > GetCtlMin(theBar))
- return;
- delta = 0;
- if (accum.v | accum.h) {
- partCode ^= 1; /* reverse direction */
- return;
- }
- bounced = true;
- syncPoint = event.where;
- partCode = 0;
- }
-
- /* see if mouse has moved sufficiently */
-
- if (delta >= deltaMin && delta <= deltaMax) {
- getEvent(&event);
- if (!triggered) {
- tracking = false;
- InitCursor();
- return; /* mouse is no longer down */
- }
- if (vBar) {
- delta = event.where.v - syncPoint.v;
- if (delta > deltaMax || delta < deltaMin) {
- theBar = vBar;
- hBar = 0;
- }
- }
- if (hBar) {
- delta = event.where.h - syncPoint.h;
- if (delta > deltaMax || delta < deltaMin) {
- theBar = hBar;
- vBar = 0;
- }
- }
- }
-
- /* request scroll */
-
- if (delta > deltaMax)
- partCode = inUpButton;
- else if (delta < deltaMin)
- partCode = inDownButton;
- }
-
-
- /*
- * getEvent
- *
- * This routine fills in an event record based on the actual mouse position,
- * or the virtual mouse position if momentum has kicked in.
- *
- * While the mouse is still down, this routine tracks the rate at which the
- * mouse has been moving, for subsequent use in the momentum calculation.
- *
- * When the mouse goes up suddenly, momentum kicks in and the virtual mouse
- * position is detached from the actual position. Subsequently the virtual
- * position is computed based on the speed the mouse was moving when it went
- * up, as degraded by friction.
- *
- */
-
- static void
- getEvent(register EventRecord *event)
- {
- static EventRecord lastEvent;
- static long rate;
- short d;
-
- /* initial call from "filterClick" */
-
- if (!tracking) {
- if (OSEventAvail(mUpMask|mDownMask, event) || (event->modifiers & btnState))
- triggered = false;
- detached = bounced = false;
- rate = 0;
- lastEvent.when = 0;
- }
-
- /* normal call from _TrackControl */
-
- else if (!detached) {
- if (OSEventAvail(mUpMask|mDownMask, event) || (event->modifiers & btnState)) {
- if (rate && opt.momentum)
- detached = true;
- else
- triggered = false;
- }
- else {
- if (event->when >= lastEvent.when + INTERVAL)
- rate = 0;
- if (vBar && event->where.v != lastEvent.where.v) {
- rate = 100L * (event->where.v - lastEvent.where.v);
- if (event->when > lastEvent.when)
- rate /= event->when - lastEvent.when;
- }
- else if (hBar && event->where.h != lastEvent.where.h) {
- rate = 100L * (event->where.h - lastEvent.where.h);
- if (event->when > lastEvent.when)
- rate /= event->when - lastEvent.when;
- }
- if (rate > MAXRATE)
- rate = MAXRATE;
- else if (rate < -MAXRATE)
- rate = -MAXRATE;
- }
- }
-
- /* momentum */
-
- if (detached) {
- if (bounced || OSEventAvail(mDownMask|keyDownMask, event) || !(event->modifiers & btnState))
- triggered = false;
- else {
- event->where = lastEvent.where;
- if (event->when > lastEvent.when) {
- d = ((event->when - lastEvent.when) * rate) / 100;
- if (d == 0)
- triggered = false;
- else if (vBar)
- event->where.v = lastEvent.where.v + d;
- else if (hBar)
- event->where.h = lastEvent.where.h + d;
- }
- }
- }
- if (event->when >= lastEvent.when + INTERVAL) {
- if (detached && opt.friction)
- rate = ((100 - FRICTION) * rate) / 100;
- lastEvent = *event;
- }
- bounced = false;
- }
-
-
- /* ---------- GetNextEvent intercept ---------- */
-
-
- /*
- * myGetNextEvent
- *
- * This routine is used to implement switching directions while "grabbing".
- * It's called when the _WaitMouseUp intercept has reported that the mouse
- * button has been released. When the application returns to its event loop,
- * we feed it a fresh click in the scroll bar to get things moving again,
- * this time in the reverse direction.
- *
- */
-
- void
- myGetNextEvent(void)
- {
- asm {
- btst #1,13(sp)
- beq.s @2
- ;
- jsr GetA4
- move.l a4,-(sp)
- movea.l (a0),a4
- tst.b tracking
- beq.s @1
- ;
- movea.l 12(sp),a0
- move.w #mouseDown,(a0)+ ; cons up an event
- clr.l (a0)+
- move.l Ticks,(a0)+
- move.l thePoint,(a0)+
- clr.w (a0)+
- movea.l (sp)+,a4
- addq.l #4,sp
- movea.l (sp)+,a0
- addq.l #6,sp
- st (sp)
- jmp (a0) ; return directly to caller
- ;
- @1 movea.l (sp)+,a4 ; chain on to real _GetNextEvent
- @2 }
- }
-
-
- /* ---------- utility routines ---------- */
-
-
- /*
- * isScrollBar - test whether a control is a scroll bar
- *
- * This routine is heuristic. A control is assumed to be a
- * scroll bar if it uses the system CDEF 1 defproc, or if it
- * uses a custom defproc and its min/max aren't 0/1.
- *
- * Controls that are invisible or dimmed are skipped.
- *
- */
-
- static Boolean
- isScrollBar(ControlHandle cH)
- {
- register ControlPtr cP = *cH;
- register struct { long pad; long type; short id; } *p;
-
- if (!cP->contrlVis || cP->contrlHilite || cP->contrlMin >= cP->contrlMax)
- return(false);
- if (cP->contrlValue < cP->contrlMin || cP->contrlValue > cP->contrlMax)
- return(false);
- p = (void *) *cP->contrlDefProc;
- if (p && p->type == 'CDEF') {
- if (p->id == 1)
- return(true);
- if (p->id == 0)
- return(false);
- }
- if (cP->contrlMin == 0 && cP->contrlMax == 1)
- return(false);
- return(true);
- }
-
-
- /*
- * localize - convert global to local coordinates
- *
- * This is somewhat like GlobalToLocal, except it doesn't touch
- * the current grafport, and it compensates for non-(0,0) origin.
- *
- */
-
- static void
- localize(Point *where, register WindowPtr wp)
- {
- Point origin;
-
- if (wp->portBits.rowBytes < 0)
- origin = topLeft((**((CGrafPtr) wp)->portPixMap).bounds);
- else
- origin = topLeft(wp->portBits.bounds);
- where->v += origin.v - wp->portRect.top;
- where->h += origin.h - wp->portRect.left;
- }
-
-
- /*
- * globalize - convert local to global coordinates
- *
- * This is somewhat like LocalToGlobal, except it doesn't touch
- * the current grafport, and it compensates for non-(0,0) origin.
- *
- */
-
- static void
- globalize(Point *where, WindowPtr wp)
- {
- Point origin;
-
- if (wp->portBits.rowBytes < 0)
- origin = topLeft((**((CGrafPtr) wp)->portPixMap).bounds);
- else
- origin = topLeft(wp->portBits.bounds);
- where->v -= origin.v - wp->portRect.top;
- where->h -= origin.h - wp->portRect.left;
- }
-
-
- /*
- * GetA4 - PC-relative access to A4
- *
- * The address of the storage used for our A4 is returned in A0.
- *
- */
-
- static void
- GetA4(void)
- {
- asm {
- bsr.s @1
- dc.l 0 ; store A4 here
- @1 move.l (sp)+,a0
- }
- }
-
-
- /* ---------- install trap and lo-mem intercepts ---------- */
-
-
- /*
- * intercept_trap - install intercept for Toolbox or OS trap
- *
- */
-
- void
- intercept_trap(register short trapno, register struct intercept *p, void *new)
- {
- register short type;
-
- if (trapno & 0x0800) {
- type = ToolTrap;
- trapno &= 0x3FF;
- }
- else {
- type = OSTrap;
- trapno &= 0xFF;
- }
- p->jsr = 0x4EB9;
- p->new = new;
- p->jmp = 0x4EF9;
- p->old = (void *) NGetTrapAddress(trapno, type);
- NSetTrapAddress(p, trapno, type);
- }
-
-
- /*
- * intercept_lomem - install intercept for lo-mem vector
- *
- */
-
- void
- intercept_lomem(short v, register struct intercept *p, void *new)
- {
- register void **vector = (void **) v;
-
- p->jsr = 0x4EB9;
- p->new = new;
- p->jmp = 0x4EF9;
- p->old = *vector;
- if (!p->old)
- p->jmp = 0x4E75;
- *vector = p;
- }
-
-
- /* ---------- INIT/cdev communication ---------- */
-
-
- /*
- * install_VBL
- *
- * We want to allow option changes made in the cdev to affect the INIT
- * immediately. (None of this "changes will take effect upon restart"
- * stuff!)
- *
- * Therefore we have to leave a pointer to the options record somewhere
- * where the cdev can find it. The vertical retrace queue seems like a
- * good place.
- *
- * Our VBL code doesn't actually do anything (except make sure it stays
- * around by resetting the vblCount each time it runs down), but it is
- * preceded by a signature that enables the cdev to find it by searching
- * the queue.
- *
- */
-
- static void
- install_VBL(void)
- {
- asm {
- lea @2,a1
- lea opt,a0
- move.l a0,-12(a1)
- lea @1,a0
- move.l a1,OFFSET(VBLTask,vblAddr)(a0)
- _VInstall
- return
- ;
- ; vbl queue entry
- ;
- @1 dc.l 0 ; qLink
- dc.w vType ; qType
- dc.l 0 ; vblAddr
- dc.w 0x7FFF ; vblCount
- dc.w 0 ; vblPhase
- ;
- ; vbl code
- ;
- dc.l 0 ; ==> options
- dc.l 'grab' ; signature
- dc.l 'INIT' ; signature
- @2 move.w #0x7FFF,OFFSET(VBLTask,vblCount)(a0)
- rts
- }
- }
-